package top.changelife.learn.springmvc.socket.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * @author cz
 * @date 2019/12/21 17:17
 */
public class NioServer {
    public static void main(String[] args) {
        try {
            ServerSocketChannel server = ServerSocketChannel.open();
            server.socket().bind(new InetSocketAddress(8080));
            // 设置为非阻塞模式
            server.configureBlocking(false);
            // 为 channel 注册选择器
            Selector selector = Selector.open();
            server.register(selector, SelectionKey.OP_ACCEPT);
            // 创建处理器
            Handler handler = new Handler();
            server:
            while (true) {
                // 等待请求，每次等待阻塞 3s
                if (selector.select(3000) == 0) {
                    System.out.println("等待请求超时......");
                    continue;
                }
                System.out.println("处理请求......");
                // 获取待处理的 SelectionKey
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    try {
                        // 接收到连接请求时 OP_ACCEPT ==> OP_READ
                        if (key.isAcceptable()) {
                            handler.handleAccept(key);
                        }
                        // 读数据 OP_READ
                        if (key.isReadable() && handler.handleRead(key).startsWith("end")) {
                            break server;
                        }
                    } catch (IOException ex) {
                        keyIterator.remove();
                    }
                    keyIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class Handler {
        private int bufferSize = 1024;
        private String localCharset = "UTF-8";

        public Handler() {
        }

        public Handler(int bufferSize) {
            this(bufferSize, null);
        }

        public Handler(String localCharset) {
            this(-1, localCharset);
        }

        public Handler(int bufferSize, String localCharset) {
            if (bufferSize > 0) {
                this.bufferSize = bufferSize;
            }
            if (localCharset != null) {
                this.localCharset = localCharset;
            }
        }

        public void handleAccept(SelectionKey key) throws IOException {
            SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
            sc.configureBlocking(false);
            sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        public String handleRead(SelectionKey key) throws IOException {
            // 获取  channel
            SocketChannel sc = (SocketChannel) key.channel();
            // 获取 buffer 并重置
            ByteBuffer buffer = ((ByteBuffer) key.attachment());
            buffer.clear();
            String receivedString = "";
            // 没有读到内容则关闭
            if (sc.read(buffer) == -1) {
                sc.close();
            } else {
                // 将 buffer 转换为读状态
                buffer.flip();
                receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
                System.out.println("receivedString: " + receivedString);
                // 返回数据给客户端
                String sendString = "received data: " + receivedString;
                buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
                sc.write(buffer);
                sc.close();
            }
            return receivedString;
        }
    }
}
